#include "cpu/exec.h"

make_EHelper(add) {
  rtl_add(&t2, &id_dest->val, &id_src->val);
  operand_write(id_dest, &t2);

  rtl_update_ZFSF(&t2, id_dest->width);

  rtl_sltu(&t0, &t2, &id_dest->val);
  rtl_set_CF(&t0);

  rtl_xor(&t0, &id_src->val, &t2);
  rtl_xor(&t1, &id_dest->val, &t2);
  rtl_and(&t0, &t0, &t1);
  rtl_msb(&t0, &t0, id_dest->width);
  rtl_set_OF(&t0);
  print_asm_template2(add);
}

make_EHelper(sub) {
  // 计算减法结果: dest = dest - src
  rtl_sub(&t2, &id_dest->val, &id_src->val); 
  // 直接写入结果
  operand_write(id_dest, &t2);
  // 更新标志位
  rtl_update_ZFSF(&t2, id_dest->width);
  rtl_sltu(&t0, &id_dest->val, &id_src->val); // CF = (dest无符号 < src无符号)
  rtl_set_CF(&t0);
  rtl_xor(&t0, &id_dest->val, &id_src->val);  // t0 = dest ^ src
  rtl_xor(&t1, &id_dest->val, &t2);           // t1 = dest ^ result
  rtl_and(&t0, &t0, &t1);                     // t0 = (dest^src) & (dest^result)
  rtl_msb(&t0, &t0, id_dest->width);          // 取最高位作为OF
  rtl_set_OF(&t0);

  print_asm_template2(sub);
}

make_EHelper(cmp) {
  // 计算减法结果: dest = dest - src
  rtl_sub(&t2, &id_dest->val, &id_src->val); 
  // 更新标志位
  rtl_update_ZFSF(&t2, id_dest->width);
  rtl_sltu(&t0, &id_dest->val, &id_src->val); // CF = (dest无符号 < src无符号)
  rtl_set_CF(&t0);
  rtl_xor(&t0, &id_dest->val, &id_src->val);  // t0 = dest ^ src
  rtl_xor(&t1, &id_dest->val, &t2);           // t1 = dest ^ result
  rtl_and(&t0, &t0, &t1);                     // t0 = (dest^src) & (dest^result)
  rtl_msb(&t0, &t0, id_dest->width);          // 取最高位作为OF
  rtl_set_OF(&t0);

  print_asm_template2(sub);
  print_asm_template2(cmp);
}

make_EHelper(inc) {
  rtl_addi(&t0, &id_dest->val, 0x1);
  operand_write(id_dest, &t0);

  rtl_update_ZFSF(&t0, id_dest->width);
  //根据位宽计算溢出标志OF
  rtlreg_t max_pos;
  switch (id_dest->width) {
    case 1: // 8位
      max_pos = 0x80;
      break;
    case 2: // 16位
      max_pos = 0x8000;
      break;
    case 4: // 32位
      max_pos = 0x80000000;
      break;
    default:
      assert(0);
  }

  // 应用位宽掩码（确保高位清零）
  rtl_andi(&t2, &t0, (id_dest->width == 4) ? 0xFFFFFFFF : 
                     (id_dest->width == 2) ? 0xFFFF : 0xFF);

  //检查是否满足溢出条件：结果 == max_pos
  rtl_eqi(&t2, &t2, max_pos);  
  rtl_set_OF(&t2);              
  print_asm_template1(inc);
}

make_EHelper(dec) {
  rtl_subi(&t0, &id_dest->val, 0x1);
  operand_write(id_dest, &t0);

  rtl_update_ZFSF(&t0, id_dest->width);
  //根据位宽计算溢出标志OF
  rtlreg_t max_pos;
  switch (id_dest->width) {
    case 1: // 8位
      max_pos = 0x7F;
      break;
    case 2: // 16位
      max_pos = 0x7FFF;
      break;
    case 4: // 32位
      max_pos = 0x7FFFFFFF;
      break;
    default:
      assert(0);
  }

  // 应用位宽掩码（确保高位清零）
  rtl_andi(&t2, &t0, (id_dest->width == 4) ? 0xFFFFFFFF : 
                     (id_dest->width == 2) ? 0xFFFF : 0xFF);

  //检查是否满足溢出条件：结果 == max_pos
  rtl_eqi(&t2, &t2, max_pos); 
  rtl_set_OF(&t2);              
  print_asm_template1(dec);
}

make_EHelper(neg) {
  rtl_sub(&t0, &tzero, &id_dest->val);
  operand_write(id_dest, &t0);

  rtl_update_ZFSF(&t0, id_dest->width);
  rtl_set_CF(&id_dest->val);

  rtlreg_t min_neg;
  switch (id_dest->width) {
    case 1: min_neg = 0x80; break;       // 8-bit
    case 2: min_neg = 0x8000; break;     // 16-bit
    case 4: min_neg = 0x80000000; break; // 32-bit
    default: assert(0);
  }
  rtl_andi(&t1, &t0, (id_dest->width == 4) ? 0xFFFFFFFF : 
                     (id_dest->width == 2) ? 0xFFFF : 0xFF);
  rtl_eqi(&t1, &t1, min_neg);
  rtl_set_OF(&t1);
  print_asm_template1(neg);
}

make_EHelper(adc) {
  rtl_add(&t2, &id_dest->val, &id_src->val);
  rtl_sltu(&t3, &t2, &id_dest->val);
  rtl_get_CF(&t1);
  rtl_add(&t2, &t2, &t1);
  operand_write(id_dest, &t2);

  rtl_update_ZFSF(&t2, id_dest->width);

  rtl_sltu(&t0, &t2, &id_dest->val);
  rtl_or(&t0, &t3, &t0);
  rtl_set_CF(&t0);

  rtl_xor(&t0, &id_dest->val, &id_src->val);
  rtl_not(&t0);
  rtl_xor(&t1, &id_dest->val, &t2);
  rtl_and(&t0, &t0, &t1);
  rtl_msb(&t0, &t0, id_dest->width);
  rtl_set_OF(&t0);

  print_asm_template2(adc);
}

make_EHelper(sbb) {
  rtl_sub(&t2, &id_dest->val, &id_src->val);
  rtl_sltu(&t3, &id_dest->val, &t2);
  rtl_get_CF(&t1);
  rtl_sub(&t2, &t2, &t1);
  operand_write(id_dest, &t2);

  rtl_update_ZFSF(&t2, id_dest->width);

  rtl_sltu(&t0, &id_dest->val, &t2);
  rtl_or(&t0, &t3, &t0);
  rtl_set_CF(&t0);

  rtl_xor(&t0, &id_dest->val, &id_src->val);
  rtl_xor(&t1, &id_dest->val, &t2);
  rtl_and(&t0, &t0, &t1);
  rtl_msb(&t0, &t0, id_dest->width);
  rtl_set_OF(&t0);

  print_asm_template2(sbb);
}

make_EHelper(mul) {
  rtl_lr(&t0, R_EAX, id_dest->width);
  rtl_mul(&t0, &t1, &id_dest->val, &t0);

  switch (id_dest->width) {
    case 1:
      rtl_sr_w(R_AX, &t1);
      break;
    case 2:
      rtl_sr_w(R_AX, &t1);
      rtl_shri(&t1, &t1, 16);
      rtl_sr_w(R_DX, &t1);
      break;
    case 4:
      rtl_sr_l(R_EDX, &t0);
      rtl_sr_l(R_EAX, &t1);
      break;
    default: assert(0);
  }

  print_asm_template1(mul);
}

// imul with one operand
make_EHelper(imul1) {
  rtl_lr(&t0, R_EAX, id_dest->width);
  rtl_imul(&t0, &t1, &id_dest->val, &t0);

  switch (id_dest->width) {
    case 1:
      rtl_sr_w(R_AX, &t1);
      break;
    case 2:
      rtl_sr_w(R_AX, &t1);
      rtl_shri(&t1, &t1, 16);
      rtl_sr_w(R_DX, &t1);
      break;
    case 4:
      rtl_sr_l(R_EDX, &t0);
      rtl_sr_l(R_EAX, &t1);
      break;
    default: assert(0);
  }

  print_asm_template1(imul);
}

// imul with two operands
make_EHelper(imul2) {
  rtl_sext(&id_src->val, &id_src->val, id_src->width);
  rtl_sext(&id_dest->val, &id_dest->val, id_dest->width);

  rtl_imul(&t0, &t1, &id_dest->val, &id_src->val);
  operand_write(id_dest, &t1);

  print_asm_template2(imul);
}

// imul with three operands
make_EHelper(imul3) {
  rtl_sext(&id_src->val, &id_src->val, id_src->width);
  rtl_sext(&id_src2->val, &id_src2->val, id_src->width);
  rtl_sext(&id_dest->val, &id_dest->val, id_dest->width);

  rtl_imul(&t0, &t1, &id_src2->val, &id_src->val);
  operand_write(id_dest, &t1);

  print_asm_template3(imul);
}

make_EHelper(div) {
  switch (id_dest->width) {
    case 1:
      rtl_li(&t1, 0);
      rtl_lr_w(&t0, R_AX);
      break;
    case 2:
      rtl_lr_w(&t0, R_AX);
      rtl_lr_w(&t1, R_DX);
      rtl_shli(&t1, &t1, 16);
      rtl_or(&t0, &t0, &t1);
      rtl_li(&t1, 0);
      break;
    case 4:
      rtl_lr_l(&t0, R_EAX);
      rtl_lr_l(&t1, R_EDX);
      break;
    default: assert(0);
  }

  rtl_div(&t2, &t3, &t1, &t0, &id_dest->val);

  rtl_sr(R_EAX, id_dest->width, &t2);
  if (id_dest->width == 1) {
    rtl_sr_b(R_AH, &t3);
  }
  else {
    rtl_sr(R_EDX, id_dest->width, &t3);
  }

  print_asm_template1(div);
}

make_EHelper(idiv) {
  rtl_sext(&id_dest->val, &id_dest->val, id_dest->width);

  switch (id_dest->width) {
    case 1:
      rtl_lr_w(&t0, R_AX);
      rtl_sext(&t0, &t0, 2);
      rtl_msb(&t1, &t0, 4);
      rtl_sub(&t1, &tzero, &t1);
      break;
    case 2:
      rtl_lr_w(&t0, R_AX);
      rtl_lr_w(&t1, R_DX);
      rtl_shli(&t1, &t1, 16);
      rtl_or(&t0, &t0, &t1);
      rtl_msb(&t1, &t0, 4);
      rtl_sub(&t1, &tzero, &t1);
      break;
    case 4:
      rtl_lr_l(&t0, R_EAX);
      rtl_lr_l(&t1, R_EDX);
      break;
    default: assert(0);
  }

  rtl_idiv(&t2, &t3, &t1, &t0, &id_dest->val);

  rtl_sr(R_EAX, id_dest->width, &t2);
  if (id_dest->width == 1) {
    rtl_sr_b(R_AH, &t3);
  }
  else {
    rtl_sr(R_EDX, id_dest->width, &t3);
  }

  print_asm_template1(idiv);
}

make_EHelper(rol) {
  uint8_t shift = id_src->val & 0x1f; // 只取低5位
  rtl_shli(&t0, &id_dest->val, shift);
  rtl_shri(&t1, &id_dest->val, id_dest->width * 8 - shift);
  rtl_or(&t2, &t0, &t1);
  operand_write(id_dest, &t2);

  // 设置标志位
  rtl_update_ZFSF(&t2, id_dest->width);
  if (shift != 0) {
    rtl_msb(&t0, &t2, id_dest->width);
    rtl_set_CF(&t0);
    if (shift == 1) {
      rtl_xor(&t0, &t2, &id_dest->val);
      rtl_msb(&t0, &t0, id_dest->width);
      rtl_set_OF(&t0);
    }
  }

  print_asm_template2(rol);
}